package com.itheima.grow.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Seconds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author 李小兵
 * @date 2015年11月14日 下午6:00:00
 */
public class DateUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(DateUtil.class);
    public static final String FORMAT_1 = "yyyyMMddHHmmss";

    public static final String FORMAT_2 = "MMdd";

    public static final String FORMAT_3 = "yyyy年MM月dd日";

    public static final String FORMAT_4 = "yyyyMMdd";

    public static final String FORMAT_5 = "yyyy-MM-dd";

    public static final String FORMAT_6 = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_7 = "HH:mm:ss";

    public static final String FORMAT_8 = "HH时mm分ss秒";

    public static final String FORMAT_9 = "mm分ss秒";

    public static final String FORMAT_10 = "ss秒";

    public static final String FORMAT_11 = "yyyy-MM-dd HH:mm";

    public static final String FORMAT_12 = "HH:mm";

    public static final String FORMAT_13 = "yyyy-MM-dd HH:mm:ss.SSS";

    public static final String FORMAT_14 = "yyyy-MM-dd HH:00:00";

    public static final String FORMAT_15 = "HH:00";

    public static final String FORMAT_16 = "YYYYMMDDHHmmssSSS";
    public static final String FORMAT_17 = "yyyyMM";
    /**
     * yyyy/MM/dd
     */
    public static final String FORMAT_18 = "yyyy/MM/dd";

    /**
     * yyyy/MM/dd HH:mm:ss
     */
    public static final String FORMAT_19 = "yyyy/MM/dd HH:mm:ss";

    public static final String FORMAT_20 = "MM/dd/yyyy HH:mm:ss";

    public static final String FORMAT_21 = "yyyy-MM-dd 00:00:00";
    /**
     * yyyy/M/dd
     */
    public static final String FORMAT_22 = "yyyy/M/dd";

    public static final String FORMAT_23 = "yyyy年MM月";

    public static final String FORMAT_25 = "yyyy/MM/dd HH:mm";

    public static final String FORMAT_24 = "MM/dd/yyyy";

    public static final String FORMAT_26 = "MM月dd日";

    /**
     * 17位时间戳
     */
    public static final String FORMAT_27 = "yyyyMMddHHmmssSSS";


    public static final int CALENDAR_DEFAULT_YEAR = 1990;

    public static final int CALENDAR_DEFAULT_MONTH = 1;

    public static final int CALENDAR_DEFAULT_DAY = 1;

    public static final String REGULAR_FORMAT_5 = "[0-9]{4}-[0-9]{2}-[0-9]{2}";

    public static final String REGULAR_FORMAT_6 = "[0-9]{4}-[0-9]{2}-[0-9]{2}\\s+[0-9]{2}:[0-9]{2}:[0-9]{2}";

    public static final String REGULAR_FORMAT_11 = "[0-9]{4}-[0-9]{2}-[0-9]{2}\\s+[0-9]{2}:[0-9]{2}";

    // 1秒等于1000毫秒
    public static final long ONE_SECOND_IN_MILLI_SECONDS = 1000;

    // 1小时等于3600秒
    public static final long ONE_HOUR_IN_SECONDS = 3600;

    // 1分钟等于60秒
    public static final long ONE_MINUTE_IN_SECONDS = 60;

    // 8小时等于28800秒
    public static final long EIGHT_HOURS_IN_SECONDS = 28800;

    /**
     * 取前几天
     */
    public static final String BEFORE = "before";

    /**
     * 取后几天
     */
    public static final String AFTER = "after";

    /**
     * 秒汉字
     */
    public static final String SECOND_CHAR = "秒";

    /**
     * 分汉字
     */
    public static final String MINUTE_CHAR = "分";

    /**
     * 时汉字
     */
    public static final String HOUR_CHAR = "时";

    /**
     * 一天的秒数
     */
    private static final Long SECONDS_OF_ONE_DAY = 86400L;

    /**
     * 东八区时区
     */
    public static final String TIMEZONE_GMT8 = "GMT+8";

    public static final int QUARTER_0 = 0;
    public static final int QUARTER_1 = 3;

    public static final int QUARTER_2 = 6;

    public static final int QUARTER_3 = 9;

    public static final int QUARTER_4 = 12;
    /**
     * 控制周数格式
     */
    private static final int NUM_WEEK = 10;
    /**
     * 年度第一周最少天数
     */
    private static final int MIN_WEEK_DAY = 4;
    private static final SimpleDateFormat YMD_SDF = new SimpleDateFormat("yyyy-MM-dd");

    public DateUtil() {
    }

    /**
     * 格式化指定的时间
     *
     * @return String
     */
    public static String formatDate(Date date, String format) {
        return formatDate(date, format, null);
    }

    /**
     * 格式化指定的时间(支持传入时区)
     *
     * @return String
     */
    public static String formatDate(Date date, String format, String timezone) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        if (StringUtils.isNotBlank(timezone)) {
            TimeZone timeZone = TimeZone.getTimeZone(timezone);
            if (Objects.nonNull(timeZone)) {
                dateFormat.setTimeZone(timeZone);
            }
        }
        return dateFormat.format(date);
    }

    /**
     * 将format格式的字符串时间格式化为yyyyMMdd的
     *
     * @param date
     * @param format
     * @return
     * @throws ParseException
     */
    public static String formatDate(String date, String format) throws ParseException {
        return formatDate(parseDate(date, format), FORMAT_4);
    }

    /**
     * 格式化当前时间
     *
     * @return String
     */
    public static String formatCurrentDate(String format) {
        return formatDate(new Date(), format);
    }

    /**
     * 获取当前时间戳
     *
     * @return String
     */
    public static String generateSystemTimestamp() {
        Date currentDate = new Date();
        return String.valueOf(currentDate.getTime());
    }

    /**
     * 获取当前时间戳
     *
     * @return String
     */
    public static String generateCurrentTimeMillis() {
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 判断firstTime是否在secondTime之后，忽略日期部分
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static boolean isOnlyTimeAfter(Date firstTime, Date secondTime) {
        Assert.notNull(firstTime, "firstTime must not be null");
        Assert.notNull(secondTime, "secondTime must not be null");

        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(firstTime);
        calendar1.set(CALENDAR_DEFAULT_YEAR, CALENDAR_DEFAULT_MONTH, CALENDAR_DEFAULT_DAY);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(secondTime);
        calendar2.set(CALENDAR_DEFAULT_YEAR, CALENDAR_DEFAULT_MONTH, CALENDAR_DEFAULT_DAY);
        return calendar1.after(calendar2);
    }

    /**
     * 判断firstTime是否在secondTime之前，忽略日期部分
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static boolean isOnlyTimeBefore(Date firstTime, Date secondTime) {
        return isOnlyTimeAfter(secondTime, firstTime);
    }

    /**
     * 获取两个date的时间差绝对值毫秒数
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static long getTimeMillisecondDifference(Date firstTime, Date secondTime) {
        long start = firstTime.getTime();
        long end = secondTime.getTime();
        return Math.abs(end - start);
    }

    /**
     * 获取两个date的时间差绝对值秒数
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static long getTimeSecondDifference(Date firstTime, Date secondTime) {
        DateTime day1 = new DateTime(firstTime);
        DateTime day2 = new DateTime(secondTime);
        return Math.abs(Seconds.secondsBetween(day1, day2).getSeconds());
    }

    /**
     * 获取两个Date的时间差绝对天数(忽略时分秒)
     *
     * @param firstDate
     * @param secondDate
     * @return
     */
    public static int getTimeDayDifference(Date firstDate, Date secondDate) {
        return getTimeDayDifference(firstDate, secondDate, true);
    }

    /**
     * 获取两个Date的时间差绝对天数
     *
     * @param firstDate
     * @param secondDate
     * @param ignoreTime 忽略时分秒
     * @return
     */
    public static int getTimeDayDifference(Date firstDate, Date secondDate, boolean ignoreTime) {
        if (ignoreTime) {
            firstDate = withDateAtStartOfDay(firstDate);
            secondDate = withDateAtStartOfDay(secondDate);
        }
        DateTime day1 = new DateTime(firstDate);
        DateTime day2 = new DateTime(secondDate);
        return Days.daysBetween(day1, day2).getDays();
    }

    /**
     * 判断firstTime是否在secondTime之后，不忽略日期部分
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static boolean isDateAndTimeAfter(Date firstTime, Date secondTime) {
        Assert.notNull(firstTime, "firstTime must not be null");
        Assert.notNull(secondTime, "secondTime must not be null");
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(firstTime);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(secondTime);
        return calendar1.after(calendar2);
    }

    /**
     * 判断firstTime是否在secondTime之前，不忽略日期部分
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static boolean isDateAndTimeBefore(Date firstTime, Date secondTime) {
        return isDateAndTimeAfter(secondTime, firstTime);
    }

    /**
     * 获取date添加minutes分钟后的时间
     *
     * @param date
     * @param minutes
     * @return
     */
    public static Date addMinutes(Date date, int minutes) {
        return DateUtils.addMinutes(date, minutes);
    }

    /**
     * 获取date添加hours时间后的时间
     *
     * @param date
     * @param hours
     * @return
     */
    public static Date addHours(Date date, int hours) {
        return DateUtils.addHours(date, hours);
    }

    /**
     * 获取date减去hours时间后的时间
     *
     * @param date
     * @param hours
     * @return
     */
    public static Date minusHours(Date date, int hours) {
        return new DateTime(date).minusHours(hours).toDate();
    }

    /**
     * 获取传入日期到当天结束时的剩余秒数
     *
     * @return
     */
    public static long getCurrentDayOverplusSeconds(Date now) {
        DateTime currentDateTime = new DateTime(now);
        DateTime lastDateTime = currentDateTime.plusDays(1).withTimeAtStartOfDay();
        return getTimeSecondDifference(currentDateTime.toDate(), lastDateTime.toDate());
    }

    /**
     * 格式化时间,忽略时分秒
     *
     * @param date
     * @return
     */
    public static Date withDateAtStartOfDay(Date date) {
        DateTime dateTime = new DateTime(date);
        return dateTime.withTimeAtStartOfDay().toDate();
    }

    /**
     * 格式化字符串为时间类型
     *
     * @param date
     * @param format
     * @return
     */
    public static Date parseDate(String date, String format) throws ParseException {
        return new SimpleDateFormat(format).parse(date);
    }

    /**
     * 格式化字符串为指定格式的时间类型(严格模式)
     *
     * @param date
     * @param format
     * @return
     */
    public static Date parseDateStrict(String date, String format) {
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            dateFormat.setLenient(false);
            return dateFormat.parse(date);
        } catch (ParseException e) {
            LOGGER.warn("格式化字符串为时间类型(严格模式)失败!", e);
            return null;
        }
    }

    public static Date formatDateToDate(Date date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        String formateDate = dateFormat.format(date);
        Date retDate = null;
        try {
            retDate = dateFormat.parse(formateDate);
        } catch (ParseException e) {
            LOGGER.warn("格式化Date类型日期失败!", e);
            return null;
        }
        return retDate;
    }

    public static Date formatDateToDate(Date date, String format, String timezone) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        if (StringUtils.isNotBlank(timezone)) {
            TimeZone timeZone = TimeZone.getTimeZone(timezone);
            if (Objects.nonNull(timeZone)) {
                dateFormat.setTimeZone(timeZone);
            }
        }
        String formateDate = dateFormat.format(date);
        Date retDate = null;
        try {
            retDate = dateFormat.parse(formateDate);
        } catch (ParseException e) {
            LOGGER.warn("格式化Date类型日期失败!", e);
            return null;
        }
        return retDate;
    }


    /**
     * 获取传入日期的前一天,忽略时分秒
     *
     * @return
     */
    public static Date getYesterdayDate(Date date) {
        return getBeforeDate(date, 1);
    }

    /**
     * 获取传入日期的天,忽略时分秒
     *
     * @param date
     * @param days
     * @return
     */
    public static Date getBeforeDate(Date date, int days) {
        DateTime yesterdayDateTime = new DateTime(date).minusDays(days).withTimeAtStartOfDay();
        return yesterdayDateTime.toDate();
    }

    /**
     * 获取指定时间指定往前几分钟的时间
     * @param date 指定时间
     * @param minutes 往前分钟数
     * @return
     */
    public static Date getBeforeMinute(Date date, int minutes) {
        DateTime dateTime = new DateTime(date).minusMinutes(minutes);
        return dateTime.toDate();
    }

    /**
     * 获取传入日期的后几天,忽略时分秒
     *
     * @param date
     * @param days
     * @return
     */
    public static Date getAfterDate(Date date, int days) {
        DateTime tomorrowDateTime = new DateTime(date).plusDays(days).withTimeAtStartOfDay();
        return tomorrowDateTime.toDate();
    }

    /**
     * 判断firstTime是否在secondTime之后,忽略时分秒
     *
     * @param firstTime
     * @param secondTime
     * @return
     */
    public static boolean isOnlyDateAfter(Date firstTime, Date secondTime) {
        Assert.notNull(firstTime, "firstTime must not be null");
        Assert.notNull(secondTime, "secondTime must not be null");
        Date firstDate = withDateAtStartOfDay(firstTime);
        Date secondDate = withDateAtStartOfDay(secondTime);
        return isDateAndTimeAfter(firstDate, secondDate);
    }

    /**
     * 秒数转为"X时X分X秒"格式的时间字符串
     *
     * @param seconds
     * @return
     */
    public static String parseTimeStringFromSeconds(long seconds) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis((seconds - EIGHT_HOURS_IN_SECONDS) * ONE_SECOND_IN_MILLI_SECONDS);
        Date date = cal.getTime();
        if (seconds >= ONE_HOUR_IN_SECONDS) {
            return formatDate(date, FORMAT_8);
        }
        if (seconds >= ONE_MINUTE_IN_SECONDS) {
            return formatDate(date, FORMAT_9);
        }
        return formatDate(date, FORMAT_10);
    }

    /**
     * 获取当前时间添加或减去指定时间的时间
     *
     * @param field
     * @param amount
     * @return
     */
    public static Date getDateOfCurrentDateAddOrSubtract(int field, int amount) {
        return getDateAddOrSubtract(new Date(), field, amount);
    }

    /**
     * 获取传入时间添加或减去指定时间的时间
     *
     * @param date
     * @param field
     * @param amount
     * @return
     */
    public static Date getDateAddOrSubtract(Date date, int field, int amount) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(field, amount);
        return new Date(calendar.getTimeInMillis());
    }

    /**
     * 判断两个日期是否相等
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean equals(final Date date1, final Date date2) {
        if (date1 == date2) {
            return true;
        }
        if (date1 == null || date2 == null) {
            return false;
        }
        return date1.equals(date2);
    }

    /**
     * 格式化字符串为时间类型(严格模式)
     *
     * @param timeString
     * @return
     */
    public static Date parseDateStrict(String timeString) {
        Date date = null;
        if (StringUtil.isMatch(REGULAR_FORMAT_5, timeString)) {
            date = parseDateStrict(timeString, FORMAT_5);
        } else if (StringUtil.isMatch(REGULAR_FORMAT_6, timeString)) {
            date = parseDateStrict(timeString, FORMAT_6);
        } else if (StringUtil.isMatch(REGULAR_FORMAT_11, timeString)) {
            date = parseDateStrict(timeString, FORMAT_11);
        }
        return date;
    }

    /**
     * 获取字符串类型日期的前几天或后几天的日期
     *
     * @param type   传入类型
     * @param date   传入日期
     * @param format 日期格式
     * @param days   天数
     * @return
     */
    public static String getBeforeOrAfterDate(String type, String date, String format, int days) {
        try {
            Date expiredDate = null;
            Date parseDate = new SimpleDateFormat(format).parse(date);
            if (BEFORE.equals(type)) {
                expiredDate = getBeforeDate(parseDate, days);
            } else if (AFTER.equals(type)) {
                expiredDate = getAfterDate(parseDate, days);
            }
            return formatDate(expiredDate, format);
        } catch (ParseException e) {
            LOGGER.warn("获取前后几天日期失败!", e);
            return null;
        }
    }

    /**
     * 两个相差秒数,转为"X天X时X分X秒"格式的时间字符串,例如86400秒为24时0分0秒
     *
     * @param seconds
     * @return
     */
    public static String parseTimeStringFromDifferentSeconds(long seconds) {
        StringBuffer timeString = new StringBuffer();
        long hour = seconds / ONE_HOUR_IN_SECONDS;
        long minute = (seconds / ONE_MINUTE_IN_SECONDS) % ONE_MINUTE_IN_SECONDS;
        long second = seconds % ONE_MINUTE_IN_SECONDS;
        timeString.append(hour == 0L ? StringUtils.EMPTY : hour + HOUR_CHAR);
        timeString.append(minute == 0L && timeString.length() == 0 ? StringUtils.EMPTY : minute + MINUTE_CHAR);
        timeString.append(second + SECOND_CHAR);
        return timeString.toString();
    }

    /**
     * 查询两个日期间所有的时间
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static List<Date> queryBetweenDayTimes(Date beginDate, Date endDate) {
        List<Date> result = new ArrayList<>();
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(beginDate);
        while (beginDate.getTime() <= endDate.getTime()) {
            result.add(tempStart.getTime());
            tempStart.add(Calendar.HOUR_OF_DAY, 1);
            beginDate = tempStart.getTime();
        }
        return result;
    }

    /**
     * 比较两个日期差值是否大于定义的天数
     *
     * @param firstTime
     * @param secondTime
     * @param days
     * @return
     */
    public static boolean isDifferenceDatesLargerThanDefinedDays(Date firstTime, Date secondTime, int days) {
        return DateUtil.getTimeSecondDifference(firstTime, secondTime) > SECONDS_OF_ONE_DAY * days;
    }

    /**
     * 第一个时间是否再第二个时间加N天之后
     *
     * @param firstTime
     * @param secondTime
     * @param day
     * @return
     */
    public static boolean isDateAndTimeAfter(Date firstTime, Date secondTime, int day) {
        Assert.notNull(firstTime, "firstTime must not be null");
        Assert.notNull(secondTime, "secondTime must not be null");
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(firstTime);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(secondTime);
        calendar2.add(Calendar.DATE, day);
        return calendar1.after(calendar2);
    }

    /**
     * 获取当前月的第一天
     *
     * @return date
     */
    public static Date getFirstDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        Date firstDay = calendar.getTime();
        return firstDay;

    }

    /**
     * 获取当前年的第一天
     *
     * @return date
     */
    public static Date getFirstDayOfYear() {
        Calendar currCal = Calendar.getInstance();
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, currCal.get(Calendar.YEAR));
        Date firstDay = calendar.getTime();
        return firstDay;

    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static Date getCurrentTime() {
        return new Date();
    }

    /**
     * 获取当前日期的本季度第一天
     *
     * @return
     */
    public static Date getCurrentQuarterStartTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;

        if (currentMonth <= QUARTER_1) {
            c.set(Calendar.MONTH, 0);
        } else if (currentMonth <= QUARTER_2) {
            c.set(Calendar.MONTH, 3);
        } else if (currentMonth <= QUARTER_3) {
            c.set(Calendar.MONTH, 6);
        } else if (currentMonth <= QUARTER_4) {
            c.set(Calendar.MONTH, 9);
        }
        c.set(Calendar.DATE, 1);
        return formatDateToDate(c.getTime(), FORMAT_21);
    }

    /**
     * 获取当前考核季度范围
     *
     * @return
     */
    public static Date[] getCurQuarter() throws ParseException {
        Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        String q1FirstDay = year + "-" + 12 + "-" + 24;
        String q2FirstDay = year + "-" + 3 + "-" + 24;
        String q3FirstDay = year + "-" + 6 + "-" + 24;
        String q4FirstDay = year + "-" + 9 + "-" + 24;
        SimpleDateFormat format = new SimpleDateFormat(FORMAT_5);
        Date q1FirstDate = format.parse(q1FirstDay);
        Date q2FirstDate = format.parse(q2FirstDay);
        Date q3FirstDate = format.parse(q3FirstDay);
        Date q4FirstDate = format.parse(q4FirstDay);
        Date[] q1 = {q1FirstDate, q2FirstDate};
        Date[] q2 = {q2FirstDate, q3FirstDate};
        Date[] q3 = {q3FirstDate, q4FirstDate};
        Date[] q4 = {q4FirstDate, q1FirstDate};
        Date now = new Date();
        if (now.after(q1FirstDate) && now.before(q2FirstDate)) {
            return q1;
        } else if (now.after(q2FirstDate) && now.before(q3FirstDate)) {
            return q2;
        } else if (now.after(q3FirstDate) && now.before(q4FirstDate)) {
            return q3;
        } else if (now.after(q4FirstDate) && now.before(q1FirstDate)) {
            return q4;
        } else {
            return null;
        }
    }

    /**
     * 获取上个考核季度范围
     *
     * @return
     */
    public static Date[] getLastQuarter() throws ParseException {
        Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        String q1FirstDay = year + "-" + 12 + "-" + 24;
        String q2FirstDay = year + "-" + 3 + "-" + 24;
        String q3FirstDay = year + "-" + 6 + "-" + 24;
        String q4FirstDay = year + "-" + 9 + "-" + 24;
        SimpleDateFormat format = new SimpleDateFormat(FORMAT_5);
        Date q1FirstDate = format.parse(q1FirstDay);
        Date q2FirstDate = format.parse(q2FirstDay);
        Date q3FirstDate = format.parse(q3FirstDay);
        Date q4FirstDate = format.parse(q4FirstDay);
        Date[] q1 = {q1FirstDate, q2FirstDate};
        Date[] q2 = {q2FirstDate, q3FirstDate};
        Date[] q3 = {q3FirstDate, q4FirstDate};
        Date[] q4 = {q4FirstDate, q1FirstDate};
        Date now = new Date();
        if (now.after(q1FirstDate) && now.before(q2FirstDate)) {
            return q4;
        } else if (now.after(q2FirstDate) && now.before(q3FirstDate)) {
            return q1;
        } else if (now.after(q3FirstDate) && now.before(q4FirstDate)) {
            return q2;
        } else if (now.after(q4FirstDate) && now.before(q1FirstDate)) {
            return q3;
        } else {
            return null;
        }
    }

    /**
     * 获取当前日期的上季度第一天
     *
     * @return
     */
    public static Date getLastQuarterFirstDay() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;

        if (currentMonth <= QUARTER_1) {
            c.set(Calendar.MONTH, 9);
        } else if (currentMonth <= QUARTER_2) {
            c.set(Calendar.MONTH, 0);
        } else if (currentMonth <= QUARTER_3) {
            c.set(Calendar.MONTH, 3);
        } else if (currentMonth <= QUARTER_4) {
            c.set(Calendar.MONTH, 6);
        }
        c.set(Calendar.DATE, 1);
        return formatDateToDate(c.getTime(), FORMAT_21);
    }

    /**
     * 日期减去年数
     *
     * @param date
     * @param yearNum
     * @return
     */
    public static Date getMinusYearFromStartDay(Date date, int yearNum) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.YEAR, -yearNum);
        return formatDateToDate(c.getTime(), FORMAT_21);
    }

    /**
     * 日期减去月数
     *
     * @param date
     * @param monthNum
     * @return
     */
    public static Date getMinusMonthFromStartDay(Date date, int monthNum) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.MONTH, -monthNum);
        return formatDateToDate(c.getTime(), FORMAT_21);
    }

    /**
     * 获取本月开始日期
     *
     * @param date
     * @return
     */
    public static Date getBeginDateOfMonth(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.DATE, 1);
        return formatDateToDate(c.getTime(), FORMAT_21);
    }

    /**
     * 判断 传入时间是否在范围内
     *
     * @param date
     * @return
     */
    public static boolean isDateBetweenStartDateAndEndDate(Date date, Date startDate, Date endDate) {
        if (date == null || startDate == null || endDate == null) {
            return false;
        }
        if (date.after(startDate) && date.before(endDate)) {
            return true;
        }
        return false;
    }

    /**
     * 判断 传入时间是否在范围内（包括等于）
     *
     * @param date
     * @return
     */
    public static boolean isDateBetweenEqStartDateAndEndDate(Date date, Date startDate, Date endDate) {
        if (date == null || startDate == null || endDate == null) {
            return false;
        }
        if (!date.before(startDate) && !date.after(endDate)) {
            return true;
        }
        return false;
    }

    /**
     * 获取当天的某指定时刻的Date数据
     *
     * @param currentDate
     * @param time
     * @return
     * @throws ParseException
     */
    public static Date getCurrentTimeForMoment(String currentDate, String time) throws ParseException {
        String substring = currentDate.substring(0, 10);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(substring);
        stringBuilder.append(time);
        String s = stringBuilder.toString();
        Date beginTime = DateUtil.parseDate(s, DateUtil.FORMAT_6);
        return beginTime;
    }

    /**
     * 获取当前时间指定时刻的前30天前的时刻
     *
     * @param currentDate
     * @param time
     * @return
     * @throws ParseException
     */
    public static Date getTimeBeforeOneMonth(String currentDate, String time) throws ParseException {
        String substring = currentDate.substring(0, 10);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(substring);
        stringBuilder.append(time);
        String s = stringBuilder.toString();
        Date beginTime = DateUtil.parseDate(s, DateUtil.FORMAT_6);
        //获取当前日期的22点减去30天的时间
        Date endTime = getDateAddOrSubtract(beginTime, 5, -30);
        return endTime;
    }

    /**
     * 根据时、分、秒获取日期
     *
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    public static Date getDateByHourOrMinuteOrSec(int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        return calendar.getTime();
    }

    /**
     * 获取指定天数的日期
     *
     * @param day
     * @return
     */
    public static Date getDateByDay(int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, day);
        return calendar.getTime();
    }

    /**
     * 获取当前时间所在本年度的第几周
     */
    public static String getWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.setMinimalDaysInFirstWeek(MIN_WEEK_DAY);
        int weekOfYear = cal.get(Calendar.WEEK_OF_YEAR);
        String week = null;
        if (weekOfYear < NUM_WEEK) {
            week = "0" + weekOfYear;
        } else {
            week = weekOfYear + "";
        }
        return week;
    }

    /**
     * 获取当前时间的年
     */
    public static String getYear() {
        String year = DateUtil.formatDate(new Date(), DateUtil.FORMAT_3);
        return year.substring(0, 5);
    }

    /**
     * 获取指定日期，时、分、秒格式的时间
     *
     * @param hour
     * @param minute
     * @param second
     * @return
     */
    public static Date getDateByDateOrHourOrMinuteOrSec(Date time, int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        return calendar.getTime();
    }

    /**
     * 获取指日期的开始时间
     */
    public static Date getDateStartTime(int day) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, day);
        Date secondDate = DateUtil.withDateAtStartOfDay(calendar.getTime());
        return secondDate;
    }

    /**
     * 获取当天的开始时间
     *
     * @return
     */
    public static Date getDayBegin() {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取当天的结束时间
     *
     * @return
     */
    public static Date getDayEnd() {
        Calendar cal = new GregorianCalendar();
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal.getTime();
    }

    /**
     * 获取昨天的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfYesterday() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    /**
     * 获取昨天的结束时间
     *
     * @return
     */
    public static Date getEndDayOfYesterday() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        return cal.getTime();
    }

    /**
     * 获取明天的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfTomorrow() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayBegin());
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获取明天的结束时间
     *
     * @return
     */
    public static Date getEndDayOfTomorrow() {
        Calendar cal = new GregorianCalendar();
        cal.setTime(getDayEnd());
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获取本周的开始时间
     *
     * @return
     */
    @SuppressWarnings("unused")
    public static Date getBeginDayOfWeek() {
        Date date = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {
            dayOfWeek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayOfWeek);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取本周的结束时间
     *
     * @return
     */
    public static Date getEndDayOfWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    /**
     * 获取上周的开始时间
     *
     * @return
     */
    @SuppressWarnings("unused")
    public static Date getBeginDayOfLastWeek() {
        Date date = new Date();
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
        if (dayofweek == 1) {
            dayofweek += 7;
        }
        cal.add(Calendar.DATE, 2 - dayofweek - 7);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取上周的结束时间
     *
     * @return
     */
    public static Date getEndDayOfLastWeek() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getBeginDayOfLastWeek());
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    /**
     * 获取本月的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取本月的结束时间
     *
     * @return
     */
    public static Date getEndDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取上月的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取上月的结束时间
     *
     * @return
     */
    public static Date getEndDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取本年的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfYear() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DATE, 1);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取下月的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfNextMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth(), 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取下月的结束时间
     *
     * @return
     */
    public static Date getEndDayOfNextMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth(), 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth(), day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取本年的结束时间
     *
     * @return
     */
    public static Date getEndDayOfYear() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, getNowYear());
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, 31);
        return getDayEndTime(cal.getTime());
    }

    /**
     * 获取某个日期的开始时间
     *
     * @param d
     * @return
     */
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某个日期的结束时间
     *
     * @param d
     * @return
     */
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取今年是哪一年
     *
     * @return
     */
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(1));
    }

    /**
     * 获取本月是哪一月
     *
     * @return
     */
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    /**
     * 两个日期相减得到的天数
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int getDiffDays(Date beginDate, Date endDate) {
        if (beginDate == null || endDate == null) {
            throw new IllegalArgumentException("getDiffDays param is null!");
        }
        long diff = (endDate.getTime() - beginDate.getTime())
                / (1000 * 60 * 60 * 24);
        int days = new Long(diff).intValue();
        return days;
    }

    /**
     * 两个日期相减得到的毫秒数
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static long dateDiff(Date beginDate, Date endDate) {
        long date1ms = beginDate.getTime();
        long date2ms = endDate.getTime();
        return date2ms - date1ms;
    }

    /**
     * 获取两个日期中的最大日期
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static Date max(Date beginDate, Date endDate) {
        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return beginDate;
        }
        return endDate;
    }

    /**
     * 获取两个日期中的最小日期
     *
     * @param beginDate
     * @param endDate
     * @return
     */
    public static Date min(Date beginDate, Date endDate) {
        if (beginDate == null) {
            return endDate;
        }
        if (endDate == null) {
            return beginDate;
        }
        if (beginDate.after(endDate)) {
            return endDate;
        }
        return beginDate;
    }

    /**
     * 返回某月该季度的第一个月
     *
     * @param date
     * @return
     */
    public static Date getFirstSeasonDate(Date date) {
        final int[] SEASON = {1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int sean = SEASON[cal.get(Calendar.MONTH)];
        cal.set(Calendar.MONTH, sean * 3 - 3);
        return cal.getTime();
    }

    /**
     * 返回某个日期下几天的日期
     *
     * @param date
     * @param i
     * @return
     */
    public static Date getNextDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + i);
        return cal.getTime();
    }

    /**
     * 返回某个日期前几天的日期
     *
     * @param date
     * @param i
     * @return
     */
    public static Date getFrontDay(Date date, int i) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) - i);
        return cal.getTime();
    }

    /**
     * 获取某年某月到某年某月按天的切片日期集合(间隔天数的集合)
     *
     * @param beginYear
     * @param beginMonth
     * @param endYear
     * @param endMonth
     * @param k
     * @return
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static List getTimeList(int beginYear, int beginMonth, int endYear,
                                   int endMonth, int k) {
        List list = new ArrayList();
        if (beginYear == endYear) {
            for (int j = beginMonth; j <= endMonth; j++) {
                list.add(getTimeList(beginYear, j, k));
            }
        } else {
            {
                for (int j = beginMonth; j < 12; j++) {
                    list.add(getTimeList(beginYear, j, k));
                }
                for (int i = beginYear + 1; i < endYear; i++) {
                    for (int j = 0; j < 12; j++) {
                        list.add(getTimeList(i, j, k));
                    }
                }
                for (int j = 0; j <= endMonth; j++) {
                    list.add(getTimeList(endYear, j, k));
                }
            }
        }
        return list;
    }

    /**
     * 获取某年某月按天切片日期集合(某个月间隔多少天的日期集合)
     *
     * @param beginYear
     * @param beginMonth
     * @param k
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static List getTimeList(int beginYear, int beginMonth, int k) {
        List list = new ArrayList();
        Calendar beginCal = new GregorianCalendar(beginYear, beginMonth, 1);
        int max = beginCal.getActualMaximum(Calendar.DATE);
        for (int i = 1; i < max; i = i + k) {
            list.add(beginCal.getTime());
            beginCal.add(Calendar.DATE, k);
        }
        beginCal = new GregorianCalendar(beginYear, beginMonth, max);
        list.add(beginCal.getTime());
        return list;
    }

    /**
     * 获取给定时间的周数
     *
     * @param date
     * @return
     */
    public static int getWeekByDate(Date date) {
        GregorianCalendar g = new GregorianCalendar();
        g.setTime(date);
        return g.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 获取给定时间的月份
     *
     * @param date
     * @return
     */
    public static int getMonthByDate(Date date) {
        GregorianCalendar g = new GregorianCalendar();
        g.setTime(date);
        return g.get(Calendar.MONTH);
    }

    /**
     * 获取给定时间的当天的某个时间
     *
     * @param date
     * @param specificTime " 09:00:00"
     * @return
     */
    public static Date getSpecificTime(Date date, String specificTime) {
        try {
            return DateUtil.parseDateStrict(String.format("%s %s", YMD_SDF.format(date), specificTime), DateUtil.FORMAT_6);
        } catch (Exception e) {
            LOGGER.warn("获取特定时刻失败!", e);
            return null;
        }
    }

    /**
     * 获取给定时间的某个时间
     *
     * @param date         特定时间
     * @param specificTime 如： "09:00:00"
     * @param n            正表示后面多少天，负数表示前面多少天
     * @return
     */
    public static Date getSpecificTime(Date date, String specificTime, int n) {
        try {
            return DateUtil.parseDateStrict(String.format("%s %s", YMD_SDF.format(DateUtil.getAfterDate(date, n)), specificTime), DateUtil.FORMAT_6);
        } catch (Exception e) {
            LOGGER.warn("获取特定时刻失败!", e);
            return null;
        }
    }

    /**
     * 日期格式MM/dd/yyyy转换为yyyy-mm-dd
     *
     * @param mdyDate
     * @return
     */
    public static String formatMdyDateToYmd(String mdyDate) {
        SimpleDateFormat oldFormat = new SimpleDateFormat(FORMAT_24);
        SimpleDateFormat newFormat = new SimpleDateFormat(FORMAT_5);
        Date date = null;
        try {
            date = oldFormat.parse(mdyDate);
        } catch (Exception e) {
            LOGGER.warn("日期格式转换失败!，入参：{}", mdyDate, e);
            return mdyDate;
        }
        return newFormat.format(date);
    }

    /**
     * 日期格式MM/dd/yyyy转换为yyyy-mm-dd
     *
     * @param mdyDate
     * @return
     */
    public static Date formatMdyDateToYmd2(String mdyDate) {
        SimpleDateFormat oldFormat = new SimpleDateFormat(FORMAT_24);
        SimpleDateFormat newFormat = new SimpleDateFormat(FORMAT_5);
        Date date = null;
        try {
            date = oldFormat.parse(mdyDate);
            return newFormat.parse(newFormat.format(date));
        } catch (Exception e) {
            LOGGER.warn("日期格式转换失败!，入参：{}", mdyDate, e);
            try {
                return newFormat.parse(mdyDate);
            } catch (Exception e2) {
                LOGGER.warn("日期格式转换失败!，入参：{}", mdyDate, e);
            }
            return null;
        }
    }

    /**
     * 获取时长换算成分钟数
     *
     * @param time
     * @return
     */
    public static long getMinutesByTime(long time) {
        long minTime = (time / ONE_SECOND_IN_MILLI_SECONDS) / ONE_MINUTE_IN_SECONDS;
        return Math.round(minTime);
    }

    /**
     * 时间格式转换成"yyyy-MM-dd HH:mm:ss"的字符串
     *
     * @param date
     * @return
     */
    public static String getStrByDate(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(FORMAT_6);
        String strDate = simpleDateFormat.format(date);
        return strDate;
    }

    /**
     * 获取当前是几号
     *
     * @return
     */
    public static int getCurrentDay() {
        Calendar cal = new GregorianCalendar();
        return cal.get(Calendar.DAY_OF_MONTH) + 1;
    }

    /**
     * 获取当前是周几
     *
     * @return
     */
    public static int getCurrentWeekDay() {
        Calendar cal = new GregorianCalendar();
        return cal.get(Calendar.DAY_OF_WEEK) - 1;
    }


    public static List<String> getDateStrFromDateStrs(String dates) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(FORMAT_5);
        String[] elements = dates.split(",");
        if (elements.length == 1) {
            return Collections.singletonList(elements[0].trim());
        }
        LocalDate startDate = LocalDate.parse(elements[0].trim(), dateTimeFormatter);
        LocalDate endDate = LocalDate.parse(elements[1].trim(), dateTimeFormatter);
        List<String> allDates = new ArrayList<>();
        for(LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            allDates.add(date.format(dateTimeFormatter));
        }
        return allDates;
    }
}
